/** serial.c
 *
 * UART
 * 
 * MM32L0
 */

//uart 寄存器
#if 0
struct uart {
	volatile unsigned long status;	/* 00 */
	volatile unsigned long data;	/* 04 */
	volatile unsigned long baud;	/* 08 */
	volatile unsigned long cr1;	/* 0c */
	volatile unsigned long cr2;	/* 10 */
	volatile unsigned long cr3;	/* 14 */
	volatile unsigned long gtp;	/* 18 - guard time and prescaler */
};
#define UART1_BASE	(struct uart *) 0x40013800
#define UART2_BASE	(struct uart *) 0x40004400
#define UART3_BASE	(struct uart *) 0x40004800
#else
struct uart{
	volatile unsigned long tdr	;	//0x00,发送数据寄存器
	volatile unsigned long rdr	;	//0x04,接收数据寄存器
	volatile unsigned long csr	;	//0x08,当前状态寄存器
	volatile unsigned long isr	;	//0x0c,中断状态寄存器
	volatile unsigned long ier	;	//0x10,中断使能寄存器
	volatile unsigned long icr	;	//0x14,中断清除寄存器
	volatile unsigned long gcr	;	//0x18,全局控制寄存器
	volatile unsigned long ccr	;	//0x1c,通用控制寄存器
	volatile unsigned long brr	;	//0x20,波特率寄存器
	volatile unsigned long frar	;	//0x24,分数波特率寄存器
};
#define UART1_BASE	(struct uart *) 0x40013800
#define UART2_BASE	(struct uart *) 0x40004400

#endif

//当前状态寄存器，低4bit有效
#define CSR_TXC			0x01		//发送结束
#define CSR_RXAVL		0x02		//接收到有效数据
#define CSR_TXFULL		0x04		//发送缓冲区满
#define CSR_TXEMPPTY	0x08		//发送缓冲区空

//中断状态寄存器，低6bit有效
#define ISR_TXEMPTY		0x01		//发送缓冲区空
#define ISR_RXAVL		0x02		//接收缓冲区接收有效数
#define ISR_RXOV		0x08		//接收缓冲区出错，接收溢出
#define ISR_RXPERR		0x10		//接收出错，奇偶校验错误
#define ISR_RXFERR		0x20		//接收出错，帧异常停止位
#define ISR_RXBRK		0x40		//接收错误，超出10bit低电平

//中断使能寄存器,低6bit有效
#define IER_TXEN		0x01		//发送缓冲区空，中断使能
#define IER_RXEN		0x02		//接收缓冲区，中断使能
#define IER_RXOVEN		0x08		//接收缓冲区溢出。中断使能
#define IER_RXPERREN	0x10		//接收奇偶校验错误，中断使能
#define IER_RXFERREN	0x20		//接收帧错误中断，中断使能
#define IER_RXBRKEN		0x40		//接收超出10个低电平，中断使能

//中断清除寄存器,低6bit有效
#define ICR_TXCLR		0x01		//发送缓冲区空，中断清除
#define ICR_RXCLR		0x02		//接收缓冲区，中断清除
#define ICR_RXOVCLR		0x08		//接收缓冲区溢出。中断清除
#define ICR_RXPERRCLR	0x10		//接收奇偶校验错误，中断清除
#define ICR_RXFERRCLR	0x20		//接收帧错误中断，中断清除
#define ICR_RXBRKCLR	0x40		//接收超出10个低电平，中断清除

//全局控制寄存器,低5bit有效
#define GCR_UARTEN		0x01		//uart模块使能
#define GCR_DMAEN		0x02		//DMA使能
#define GCR_AFEN		0x04		//自动流控使能
#define GCR_RXEN		0x08		//接收使能
#define GCR_TXEN		0x10		//发送使能

//通用控制寄存器,低6bit有效
#define CCR_PEN			0x01		//奇偶校验使能
#define CCR_PSEL		0x02		//校验选择0:奇校验 1:偶校验
#define CCR_SPB			0x04		//停止位选择 0:1个停止位  1:2个停止位
#define CCR_BRK			0x08		//强制发送断开帧
#define CCR_D5			0x00		// 2bit 选择数据宽度,5bit
#define CCR_D6			0x10		// 6bit
#define CCR_D7			0x20		// 7bit
#define CCR_D8			0x40		// 8bit

//


static void uart_init ( struct uart *up, int baud )
{
	//1个停止位，禁止校验，
	up->ccr = CCR_D8;
	up->gcr = GCR_UARTEN | GCR_RXEN | GCR_TXEN;

	//mm32l0xx 的uart有小数分频，更精确
	if ( up == UART1_BASE )
	    up->brr = get_pclk2() / baud;
	else
	    up->brr = get_pclk1() / baud;
}

void
serial_init ( void )
{
	gpio_uart1 ();
	// uart_init ( UART1_BASE, 9600 );
	// uart_init ( UART1_BASE, 38400 );
	// uart_init ( UART1_BASE, 57600 ); ??
	uart_init ( UART1_BASE, 115200 );

#ifdef notdef
	gpio_uart2 ();
	uart_init ( UART2_BASE, 9600 );

	gpio_uart3 ();
	uart_init ( UART3_BASE, 9600 );
#endif
}

void serial_putc ( int c )
{
	struct uart *up = UART1_BASE;

	if ( c == '\n' )
	    serial_putc ( '\r' );

	while ( ! (up->csr & CSR_TXEMPPTY) )	//发送缓冲区为空
	    ;
	up->tdr = c;
}

void serial_puts ( char *s )
{
	while ( *s )
	    serial_putc ( *s++ );
}

/* -------------------------------------------- */
/* Some IO stuff from Kyu */
/* -------------------------------------------- */

#define HEX(x)  ((x)<10 ? '0'+(x) : 'A'+(x)-10)

#define PUTCHAR(x)      *buf++ = (x)

static char *
shex2( char *buf, int val )
{
        PUTCHAR( HEX((val>>4)&0xf) );
        PUTCHAR( HEX(val&0xf) );
        return buf;
}

static char *
shex4( char *buf, int val )
{
        buf = shex2(buf,val>>8);
        return shex2(buf,val);
}

static char *
shex8( char *buf, int val )
{
        buf = shex2(buf,val>>24);
        buf = shex2(buf,val>>16);
        buf = shex2(buf,val>>8);
        return shex2(buf,val);
}

void
show16 ( char *s, int val )
{
	char buf[5];

	serial_puts ( s );
	shex4 ( buf, val );
	buf[4] = '\0';
	serial_puts ( buf );
	serial_putc ( '\n' );
}

/* THE END */
